/**
 * @description: Geolocation service.
 * @author: pkeros.
 * @date: 26/09/2017.
 * @mail: pkeros@vip.qq.com
 */

// 地理位置刷新间隔
const GEO_REFRESH_TIME = 3000;
let geolocationInstance = null;

class Geolocation {

  gAMap = window.AMap;
  amapInstance = null;
  Geocoder = null;
  gelocationWatchs = [];
  currentCityCode = '0512';
  currentPosition = null;

  /**
   * @desc 构造函数
   */
  constructor () {
    this.amapInstance = new this.gAMap.Map('station');
    this.amapInstance.plugin([
      'AMap.LngLat',
      'AMap.Geocoder',
      'AMap.convertFrom',
      'AMap.Autocomplete',
      'AMap.PlaceSearch',
      'AMap.LineSearch',
      'AMap.StationSearch'
    ], () => {
      // 实例化地理位置逆编码服务
      this.Geocoder = new this.gAMap.Geocoder();

      // 定时刷新地理位置信息
      this.refreshCurrentPosition();
      setInterval(() => this.refreshCurrentPosition(), GEO_REFRESH_TIME);

      // 添加地理位置变动的监听器
      this.addWatch(function ({ position }) {
        console.info('地理位置变更!', position);
        this.currentPosition = position;
      }, this);
    })
  }

  /**
   * @desc 默认错误处理函数
   * @param err
   */
  errHandle (err) {
    throw new Error(err.message);
  }

  /**
   * @desc 刷新当前地理位置信息
   */
  refreshCurrentPosition () {
    window.wx.getLocation({success: ({longitude, latitude}) => {
      this.gAMap.convertFrom(new this.gAMap.LngLat(longitude, latitude), 'gps', (status, {locations}) => {
        if (status !== 'complete') {return}

        // 判断地理位置是否更变
        if (String(this.currentPosition) === String(locations[0])) { return }

        this.currentPosition = locations[0];
        this.gelocationWatchs.forEach(({func, scope}) => {func.call(scope, {position: locations[0]})});
        this.Geocoder.getAddress(locations[0], (status, {regeocode: {addressComponent: {citycode}}}) => {
          if (status !== 'complete') {return}

          this.currentCityCode = citycode;
        });
      });
    }});
  }

  /**
   * @desc 计算当前所在位置到某个地理位置坐标之间的距离
   * @param position {Object} 高德 LngLat 对象
   * @return {Number} 两点距离的位置
   */
  calcCurrent2TargetDistance (position) {
    if (!this.getCurrentPosition())
      return null;

    return this.getCurrentPosition().distance(position)
  }

  /**
   * @desc 获取当前地理位置信息
   * @return {Object}
   */
  getCurrentPosition () {
    if (!this.currentCityCode)
      throw new Error('未获取到地理位置信息!');

    return this.currentPosition;
  }

  /**
   * @desc 获取当前城市代码
   * @return {String} city code.
   */
  getCurrentCityCode () {
    if (!this.currentCityCode)
      throw new Error('未获取到地理位置信息!');

    return this.currentCityCode;
  }

  /**
   * @desc 清除所有监听
   */
  clearAllWatch () {
    this.gelocationWatchs.forEach(({id}) => this.gelocation.clearWatch(id));
  }

  /**
   * @desc 清除监听
   * @param id {*}
   */
  clearWatch (id = () => {throw new Error('没有 ID 你清除个几把! ')}) {
    this.gelocation.clearWatch(this.gelocationWatchs[id].id);
  }

  /**
   * @desc 添加一个地理位置更变监听
   * @param func {Function} 回调函数
   * @param scope {Object} 作用域
   * @param err {Function} 错误处理函数
   * @return {Number} 监听 ID
   */
  addWatch(func, scope, err = this.errHandle) {
    this.gelocationWatchs.push({func: func, scope: scope, err: err});

    return this.gelocationWatchs.length - 1;
  }
}

export default new class _ {
  /**
   * @desc 初始化 Geolocation 对象
   */
  init () {
    geolocationInstance = new Geolocation();
  }

  /**
   * @desc 获取 Geolocation 对象实例
   * @return {*}
   */
  getInstance () {
    if (!geolocationInstance) { throw new Error('geolocation 未初始化，请先调用 init 方法!') }

    return geolocationInstance;
  }
};
